-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Introduce application containers #7162
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
dd5dd51
to
4f226f9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the quick draft, @KyleAure ! I'm really excited about this. I've left some comments and suggestions.
modules/liberty/src/main/java/org/testcontainers/containers/LibertyContainer.java
Outdated
Show resolved
Hide resolved
modules/liberty/src/main/java/org/testcontainers/containers/LibertyContainer.java
Outdated
Show resolved
Hide resolved
modules/liberty/src/main/java/org/testcontainers/containers/LibertyContainer.java
Outdated
Show resolved
Hide resolved
modules/liberty/src/main/java/org/testcontainers/containers/LibertyContainer.java
Outdated
Show resolved
Hide resolved
...s/application-platform/src/main/java/org/testcontainers/containers/ApplicationContainer.java
Outdated
Show resolved
Hide resolved
...s/application-platform/src/main/java/org/testcontainers/containers/ApplicationContainer.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @KyleAure ! I have left some comments. Please, also run ./gradlew spotlessApply
and let's take into account the Java version baseline for Testcontainers is 8.
* @param archives - An archive created using shrinkwrap and test runtime | ||
* @return self | ||
*/ | ||
public ApplicationServerContainer withArchvies(@NonNull Archive<?>... archives) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public ApplicationServerContainer withArchvies(@NonNull Archive<?>... archives) { | |
public ApplicationServerContainer withArchives(@NonNull Archive<?>... archives) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, we would like to be more open about how the archive is provided. WDYT about receiving File... archives
instead?
AFAIK we can do something like this.
WebArchive archive = ShrinkWrap.create(WebArchive.class,"jakarta-tc.war")
.addClass(App.class)
.addPackages(true,
"dev.wittek.tc.jakarta.book",
"dev.wittek.tc.jakarta.dice",
"dev.wittek.tc.jakarta.time",
"dev.wittek.tc.jakarta.turing")
.addAsResource("META-INF/persistence.xml")
.addAsResource("META-INF/init.sql")
.addAsResource("turing.csv")
.addAsLibraries(deps);
archive.as(ZipExporter.class).exportTo(Paths.get("target/jakarta-tc.war").toFile(), true);
This way we can support those using ShrinkWrap and those who doesn't
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed spelling error.
I think having native ShrinkWrap support would really help with ease of use.
If users are looking to replace Arquillian with TestContainers then those users will never have had to export their archives to the host system since Arquillian takes care of that behind the scenes.
Without this kind of support I'd say it isn't even worth creating the ApplicationContainer and users could just use a GenericContainer. ShrinkWrap is the value add here.
This way we can support those using ShrinkWrap and those who do not
This is achievable with the pre-existing method:
public ApplicationServerContainer withArchives(@NonNull MountableFile... archives)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I built some examples for JakartaOne and ShrinkWrap play nice with Testcontainers by using Transferable.of(byte[])
.
...r-commons/src/main/java/org/testcontainers/applicationserver/ApplicationServerContainer.java
Outdated
Show resolved
Hide resolved
...r-commons/src/main/java/org/testcontainers/applicationserver/ApplicationServerContainer.java
Outdated
Show resolved
Hide resolved
* @param httpPort - The HTTP port used by the Application platform | ||
* @return self | ||
*/ | ||
public ApplicationServerContainer withHttpPort(int httpPort) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please elaborate more on the use cases for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the port a user would use to connect to their application.
Similar to the database containers we want to be able to construct a connection URL for testing getApplicationURL()
.
It is common for application containers to be configured with a different port than the default.
Example:
private static ApplicationServerContainer liberty = new LibertyServerContainer(libertyImage)
.withArchives(createDeployment())
.withAppContextRoot("test/app/service/")
.withHttpPort(80);
@Test
public void testURL() {
String actual = liberty.getApplicationURL();
String expected = "http://localhost:35286/test/app/service" //where 35286 maps to port 80
assertThat(actual).isEqualTo(expected);
}
You could argue that we could just rely on firstMappedPort
but for future iterations, I could see us adding in withHttpsPort
and getSecureApplicationURL()
which wouldn't be able to relay on that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is common for application containers to be configured with a different port than the default.
even for testing? Just curious. I mean, it can be done but I was not expecting it in testing, at least not very often.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, if I am an application developer who wants to do integration testing I will have my test application server configured to the same specification as my production application server. Most applications do not run on the default port 9080
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest to move the method body to the configure
method. The logic about replacePort
, appendPort
seems a little bit odd here. I think we don't need to overwrite setExposedPorts
neither.
Tests in ApplicationServerContainerTest
should call configure
before getExposedPorts()
in order to get the proper container configuration. Also, I'm not sure order is required for ports. LMK if I'm missing something
Please, also add tests when readinessPort is set.
modules/liberty/src/main/java/org/testcontainers/containers/LibertyServerContainer.java
Outdated
Show resolved
Hide resolved
modules/liberty/src/main/java/org/testcontainers/containers/LibertyServerContainer.java
Outdated
Show resolved
Hide resolved
modules/liberty/src/main/java/org/testcontainers/containers/LibertyServerContainer.java
Outdated
Show resolved
Hide resolved
modules/liberty/src/main/java/org/testcontainers/containers/LibertyServerContainer.java
Outdated
Show resolved
Hide resolved
modules/liberty/src/main/java/org/testcontainers/containers/LibertyServerContainer.java
Outdated
Show resolved
Hide resolved
b957fd8
to
2a0359c
Compare
@eddumelendez Responded to your review comments and updated where necessary. As for running the
I've tried uninstalling and reinstalling node multiple times and I honestly cannot get this gradle task working. ** got this working on another system and pushed the spotless changes ** |
modules/liberty/src/main/java/org/testcontainers/containers/LibertyServerContainer.java
Outdated
Show resolved
Hide resolved
@@ -0,0 +1,56 @@ | |||
# Liberty Containers |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In order to display the docs we should add a section Application Servers
just like we have it for databases
testcontainers-java/mkdocs.yml
Lines 48 to 49 in 8465795
- Modules: | |
- Databases: |
import jakarta.ws.rs.Consumes; | ||
import jakarta.ws.rs.GET; | ||
import jakarta.ws.rs.Path; | ||
import jakarta.ws.rs.Produces; | ||
import jakarta.ws.rs.core.MediaType; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests failed because of the Java version. Currently, Testcontainers uses Java 8 but we can perform tests with other version declaring the following in the build.gradle
testcontainers-java/modules/oracle-xe/build.gradle
Lines 21 to 32 in 8465795
test { | |
javaLauncher = javaToolchains.launcherFor { | |
languageVersion = JavaLanguageVersion.of(11) | |
} | |
} | |
compileTestJava { | |
javaCompiler = javaToolchains.compilerFor { | |
languageVersion = JavaLanguageVersion.of(11) | |
} | |
options.release.set(11) | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@KyleAure few more comments
// Container defaults | ||
static final int DEFAULT_HTTP_PORT = 9080; | ||
|
||
static final int DEFAULT_HTTPS_PORT = 9443; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unused for now. So, it can be removed.
|
||
@GET | ||
public String getAll() { | ||
System.out.println("Calling getAll"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can remove the println
calls
//This is unintuitive and should have a better solution. | ||
|
||
// configureLiberty { | ||
liberty.withEnv("DB_URL", mockDatabase.getNetworkAliases().get(0) + ":1080"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use the network alias instead to be explicit. Otherwise, the network alias mockDatabase
declared in MockServerContainer is not being used.
liberty.withEnv("DB_URL", mockDatabase.getNetworkAliases().get(0) + ":1080"); | |
liberty.withEnv("DB_URL", "mockDatabase:1080"); |
|
||
//Note cannot use mockDatabase.getEndpoint() since it will return http://localhost:56254 when instead we need http://mockDatabase:1080 | ||
//This is unintuitive and should have a better solution. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When using container networks, services can call each other through the network alias and the direct port. That's how it is done in docker-compose. I agree that in order to know the ports right now can be challenging but I think javadocs around it can help. That's something to tackle around all Testcontainers modules.
//Note cannot use mockDatabase.getEndpoint() since it will return http://localhost:56254 when instead we need http://mockDatabase:1080 | |
//This is unintuitive and should have a better solution. |
public ApplicationServerContainer(@NonNull final Future<String> image) { | ||
super(image); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not being used. It can be removed.
private Duration httpWaitTimeout = Duration.ofSeconds(60); | ||
|
||
// Expected path for Microprofile platforms to query for readiness | ||
static final String MP_HEALTH_READINESS_PATH = "/health/ready"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is not being used.
* @return self | ||
*/ | ||
public ApplicationServerContainer withAppContextRoot(@NonNull String appContextRoot) { | ||
if (Objects.nonNull(this.appContextRoot) && this.appContextRoot == this.readinessPath) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (Objects.nonNull(this.appContextRoot) && this.appContextRoot == this.readinessPath) { | |
if (Objects.nonNull(this.appContextRoot) && this.appContextRoot.equals( this.readinessPath)) { |
if (path.matches(".*\\.jar|.*\\.war|.*\\.ear|.*\\.rar")) { | ||
return path.substring(path.lastIndexOf("/")); | ||
} | ||
throw new IllegalArgumentException("File did not contain an application archive"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
throw new IllegalArgumentException("File did not contain an application archive"); | |
throw new IllegalArgumentException("File did not contain a valid application archive"); |
* @param httpPort - The HTTP port used by the Application platform | ||
* @return self | ||
*/ | ||
public ApplicationServerContainer withHttpPort(int httpPort) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest to move the method body to the configure
method. The logic about replacePort
, appendPort
seems a little bit odd here. I think we don't need to overwrite setExposedPorts
neither.
Tests in ApplicationServerContainerTest
should call configure
before getExposedPorts()
in order to get the proper container configuration. Also, I'm not sure order is required for ports. LMK if I'm missing something
Please, also add tests when readinessPort is set.
This is a draft PR to further explore the development of application platform containers.
Related Issue #7098